using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#if ODIN_INSPECTOR
using Sirenix.OdinInspector;
#endif
using UnityEngine;
using Object = UnityEngine.Object;


namespace JH
{
    /// <summary>
    ///  依赖注入管理类，为了避免
    /// </summary>
    [DefaultExecutionOrder(-100)]
    public class InjectManager : MonoBehaviour
    {
        /// <summary>
        ///  存储所有可以用来注入的实例,key为类型，value为实例集合
        /// </summary>
        private readonly ConcurrentDictionary<Type, List<WeakReference<object>>> _totalInstances = new();

        /// <summary>
        ///  存储所有带有特性标记的实例 key为实例，value为这个实例标记有注入特性的成员集合
        /// </summary>
        private readonly ConcurrentDictionary<WeakReference<object>, List<MemberInfo>> _weakAttributes = new();

        private void Awake()
        {
            Inject();
        }
#if ODIN_INSPECTOR && UNITY_EDITOR
        [Button("编辑器注入")]
#endif
#if UNITY_EDITOR
        [ContextMenu("编辑器注入")]
        private void EditorInject()
        {
            EditorInjector.Inject();
        }
#endif
        private void OnValidate()
        {
#if UNITY_EDITOR
            EditorInject();
#endif
        }

        /// <summary>
        ///  依赖注入函数
        /// </summary>
        private void Inject()
        {
            // 收集所有可以注入的实例
            CollectInstances();

            // 收集所有带有特性标记的实例
            CollectAttributes();

            // 进行依赖注入
            DoInject();
        }

        /// <summary>
        ///  进行依赖注入
        /// </summary>
        private void DoInject()
        {
            RuntimeInjector.DoInject(_totalInstances, _weakAttributes);
        }

        /// <summary>
        ///  收集所有带有特性标记的实例
        /// </summary>
        private void CollectAttributes()
        {
            var find = typeof(InjectAttribute).GetObjectMemberInfosByAttributeEm<MonoBehaviour>(true);
            foreach (var entry in find)
            {
                // 获取弱引用
                var key = entry.Key as object;

                // 获取标记的成员
                var members = entry.Value;

                // 添加到字典中
                _weakAttributes.TryAdd(new WeakReference<object>(key), members.ToList());
            }
        }

        /// <summary>
        ///  收集所有可以用来注入的实例
        /// </summary>
        private void CollectInstances()
        {
            // 收集所有Component实例
            CollectComponentInstances();

            // 添加常规实例
            AddNormalClasses();
        }

        /// <summary>
        ///  添加所有Component实例
        /// </summary>
        private void CollectComponentInstances()
        {
            // 寻找所有Object实例
            var allObjects = FindObjectsByType<Component>(FindObjectsInactive.Include, FindObjectsSortMode.None);

            // 逐个添加Object实例
            foreach (var each in allObjects)
            {
                // 获取类型
                var type = each.GetType();

                // 添加单个可注入的实例
                AddEachInjectableInstance(type, each);
            }
        }

        /// <summary>
        /// 添加常规实例，用于处理所有继承自 IInjectable 的非 MonoBehaviour 类型的类。
        /// 该函数会对类型进行依赖分析，处理循环依赖，并优先实例化没有依赖的类型。
        /// </summary>
        private void AddNormalClasses()
        {
            // 1. 找到所有继承自 IInjectable 的类
            var types = typeof(IInjectable).GetAllDerivedTypesEm();

            // 2. 排除掉不符合条件的类型，包括继承自 Component 的类型、接口、抽象类、泛型定义和泛型参数
            types = types.Where(t => !t.IsSubclassOf(typeof(Component)) && !t.IsInterface
                                                                        && !t.IsAbstract &&
                                                                        !t.IsGenericTypeDefinition &&
                                                                        !t.IsGenericParameter)
                .ToList();

            // 3. 对类型列表进行依赖分析，检测是否存在循环依赖，如果检测到循环依赖，直接抛出异常
            if (HasCircularDependencies(types))
                throw new InvalidOperationException("检测到类型之间存在循环依赖，无法完成实例化。");

            // 4. 对类型进行拓扑排序，确保依赖的类型优先实例化
            var sortedTypes = TopologicalSort(types);

            // 5. 按依赖顺序逐个实例化类型
            foreach (var type in sortedTypes)
            {
                // 查找所有构造函数，从参数数量由多到少排序
                var constructors = type.GetConstructors()
                    .OrderByDescending(ctor => ctor.GetParameters().Length)
                    .ToList();

                // 尝试匹配一个可用的构造函数
                object instance = null;
                foreach (var constructor in constructors)
                {
                    // 获取构造函数的参数信息
                    var parameters = constructor.GetParameters();

                    // 如果没有参数，直接实例化
                    if (parameters.Length == 0)
                    {
                        instance = Activator.CreateInstance(type);
                        break;
                    }

                    // 为构造函数的参数寻找实例
                    var parameterInstances = new List<object>();
                    bool canResolveAllParameters = true;

                    foreach (var parameter in parameters)
                    {
                        // 从已注册的实例中查找依赖的参数
                        var parameterType = parameter.ParameterType;
                        if (TryGetInjectableInstance(parameterType, out var dependency))
                        {
                            parameterInstances.Add(dependency);
                        }
                        else
                        {
                            // 如果有任何参数无法解析，跳过该构造函数
                            canResolveAllParameters = false;
                            break;
                        }
                    }

                    // 如果成功匹配所有参数，使用该构造函数实例化对象
                    if (canResolveAllParameters)
                    {
                        instance = constructor.Invoke(parameterInstances.ToArray());
                        break;
                    }
                }

                // 如果实例化失败，抛出异常
                if (instance == null)
                {
                    throw new InvalidOperationException($"无法为类型 {type.FullName} 找到合适的构造函数进行实例化。");
                }

                // 6. 将实例添加到字典中
                AddEachInjectableInstance(type, instance);
            }
        }

        /// <summary>
        /// 检测是否存在循环依赖
        /// </summary>
        /// <param name="types">类型列表</param>
        /// <returns>是否存在循环依赖</returns>
        private bool HasCircularDependencies(List<Type> types)
        {
            // 构建依赖图
            var dependencyGraph = new Dictionary<Type, List<Type>>();
            foreach (var type in types)
            {
                // 获取构造函数参数中依赖的类型
                var dependencies = type.GetConstructors()
                    .SelectMany(ctor => ctor.GetParameters())
                    .Select(parameter => parameter.ParameterType)
                    .Where(types.Contains) // 只记录在当前类型集合中的依赖
                    .ToList();

                dependencyGraph[type] = dependencies;
            }

            // 检测图中是否存在循环
            var visited = new HashSet<Type>();
            var recursionStack = new HashSet<Type>();

            bool HasCycle(Type current)
            {
                if (recursionStack.Contains(current)) return true;
                if (!visited.Add(current)) return false;

                recursionStack.Add(current);

                foreach (var dependency in dependencyGraph[current])
                {
                    if (HasCycle(dependency)) return true;
                }

                recursionStack.Remove(current);
                return false;
            }

            return types.Any(HasCycle);
        }

        /// <summary>
        /// 对类型进行拓扑排序，确保依赖的类型优先实例化
        /// </summary>
        /// <param name="types">类型列表</param>
        /// <returns>拓扑排序后的类型列表</returns>
        private List<Type> TopologicalSort(List<Type> types)
        {
            var dependencyGraph = new Dictionary<Type, List<Type>>();
            foreach (var type in types)
            {
                var dependencies = type.GetConstructors()
                    .SelectMany(ctor => ctor.GetParameters())
                    .Select(parameter => parameter.ParameterType)
                    .Where(types.Contains)
                    .ToList();

                dependencyGraph[type] = dependencies;
            }

            var sorted = new List<Type>();
            var visited = new HashSet<Type>();

            void Visit(Type current)
            {
                if (!visited.Add(current)) return;

                foreach (var dependency in dependencyGraph[current])
                {
                    Visit(dependency);
                }

                sorted.Add(current);
            }

            foreach (var type in types)
            {
                Visit(type);
            }

            return sorted;
        }

        /// <summary>
        /// 尝试从已注册的实例中获取依赖
        /// </summary>
        /// <param name="type">依赖的类型</param>
        /// <param name="instance">返回的实例</param>
        /// <returns>是否成功找到依赖</returns>
        private bool TryGetInjectableInstance(Type type, out object instance)
        {
            instance = null;

            // 从已注册的实例字典中查找
            if (_totalInstances.TryGetValue(type, out var instances))
            {
                var validInstance = instances.FirstOrDefault(wr => wr.TryGetTarget(out _));
                if (validInstance != null && validInstance.TryGetTarget(out var target))
                {
                    instance = target;
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        ///  添加单个可注入的实例
        /// </summary>
        private void AddEachInjectableInstance(Type type, object obj)
        {
            // 从当前类型一直到基类型，都依次加入到字典中
            while (type != null && type != typeof(Object))
            {
                // 初始化或更新字典中的实例列表
                _totalInstances.AddOrUpdate(type, _ => new List<WeakReference<object>> { new(obj) },
                    (_, existingList) =>
                    {
                        // 如果该类型已经存在于字典中，添加新的弱引用
                        if (!existingList.Any(wr => wr.TryGetTarget(out var target) && target == obj))
                        {
                            existingList.Add(new WeakReference<object>(obj));
                        }

                        return existingList;
                    });

                // 获取父类
                type = type.BaseType;
            }

            // 获取所有接口，并将其依次注册到字典中
            var interfaces = obj.GetType().GetInterfaces();
            foreach (var interfaceType in interfaces)
            {
                _totalInstances.AddOrUpdate(
                    interfaceType,
                    _ => new List<WeakReference<object>> { new(obj) },
                    (_, existingList) =>
                    {
                        // 如果接口类型已经存在于字典中，添加新的弱引用
                        if (!existingList.Any(wr => wr.TryGetTarget(out var target) && target == obj))
                        {
                            existingList.Add(new WeakReference<object>(obj));
                        }

                        return existingList;
                    });
            }
        }
    }
}